package com.qqtech.qquan.user.service;

import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Service;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.qqtech.core.common.cache.Cache;
import com.qqtech.core.common.constant.CoreConst;
import com.qqtech.core.common.enums.SexEnum;
import com.qqtech.core.common.enums.YesNoEnum;
import com.qqtech.core.common.exception.BizzException;
import com.qqtech.core.common.exception.LoginException;
import com.qqtech.core.common.util.PinyingUtil;
import com.qqtech.core.common.util.SettingCfgUtil;
import com.qqtech.core.common.util.StringUtil;
import com.qqtech.core.common.util.TimeUtil;
import com.qqtech.core.frame.dao.BaseDao;
import com.qqtech.core.frame.model.PageKit;
import com.qqtech.core.frame.model.PageOrder;
import com.qqtech.core.frame.model.Result;
import com.qqtech.core.frame.service.BaseServiceImpl;
import com.qqtech.qquan.coupon.enums.CouponBaseBizzTypeDictEnum;
import com.qqtech.qquan.coupon.enums.CouponUserObtainWayDictEnum;
import com.qqtech.qquan.coupon.model.CouponBaseQuery;
import com.qqtech.qquan.coupon.model.CouponBaseVo;
import com.qqtech.qquan.coupon.service.CouponBaseService;
import com.qqtech.qquan.coupon.service.CouponUserService;
import com.qqtech.qquan.hi.enums.HiRuleTaskTypeDictEnum;
import com.qqtech.qquan.hi.service.HiCommunityService;
import com.qqtech.qquan.hi.service.HiUserService;
import com.qqtech.qquan.hi.service.HiUserTaskService;
import com.qqtech.qquan.im.service.ImUserService;
import com.qqtech.qquan.user.cache.UserSysParamCache;
import com.qqtech.qquan.user.dao.UserIdentityDao;
import com.qqtech.qquan.user.dao.UserLoginDao;
import com.qqtech.qquan.user.enums.UserConst;
import com.qqtech.qquan.user.enums.UserIdentityTypeDictEnum;
import com.qqtech.qquan.user.enums.UserValueOsTypeDictEnum;
import com.qqtech.qquan.user.enums.UserVerifycodeTypeDictEnum;
import com.qqtech.qquan.user.model.UserAuth;
import com.qqtech.qquan.user.model.UserBase;
import com.qqtech.qquan.user.model.UserIdentity;
import com.qqtech.qquan.user.model.UserIdentityQuery;
import com.qqtech.qquan.user.model.UserIdentityVo;
import com.qqtech.qquan.user.model.UserLogin;
import com.qqtech.qquan.user.model.UserLoginVo;
import com.qqtech.qquan.user.model.UserValue;
import com.qqtech.qquan.user.model.UserVerifycode;

@Service
public class UserLoginServiceImpl extends BaseServiceImpl<UserLogin>
		implements UserLoginService, Cache<String, UserLoginVo> {
	public static final Logger log = LoggerFactory.getLogger(UserLoginServiceImpl.class);
	@Resource
	private UserSysParamCache userSysParamCache;
	@Resource
	private UserIdentityDao userIdentityDao;

	@Resource
	private UserLoginDao userLoginDao;

	@Resource
	private ImUserService imUserService;
	@Resource
	private UserValueService userValueService;

	@Resource
	private UserMoneyLogService userMoneyLogService;

	@Resource
	private CouponBaseService couponBaseService;

	@Resource
	private CouponUserService couponUserService;
	@Resource
	private HiUserService hiUserService;
	@Resource
	private HiUserTaskService hiUserTaskService;
	@Resource
	private HiCommunityService hiCommunityService;

	@Override
	protected BaseDao<UserLogin> getBaseDao() {
		return userLoginDao;
	}

	@Resource
	private UserVerifycodeService userVerifycodeService;
	@Resource
	private UserIdentityService userIdentityService;
	@Resource
	private UserBaseService userBaseService;
	@Resource
	private UserLoginService userLoginService;

	@Resource
	private UserAuthService userAuthService;

	private LoadingCache<String, UserLoginVo> caches = CacheBuilder.newBuilder().recordStats()
			.expireAfterWrite(
					SettingCfgUtil.getConfigHelper("qquan-cfg.properties").getIntValue("paramcache.expire.mins"),
					TimeUnit.MINUTES)
			.build(new CacheLoader<String, UserLoginVo>() {
				public UserLoginVo load(String token) throws LoginException {
					UserLoginVo userLoginVo = userLoginService.getByToken(token);
					if (userLoginVo == null) {
						throw new LoginException(CoreConst.VALUE_CORE_UNLOGIN_MSG);
					}
					return userLoginVo;
				}
			});

	@Override
	public UserLoginVo getCacheByToken(String token) {
		return this.get(token);
	}

	@Override
	public UserLoginVo get(String token) {
		return cacheValue(token);
	}

	public UserLoginVo cacheValue(String token) {
		return caches.getUnchecked(token);
	}

	@Override
	public void clear(String token) {
		caches.invalidate(token);
	}

	@Override
	public void clearAll() {
		caches.invalidateAll();
	}

	@Override
	public UserLoginVo getByToken(String token) {
		if (StringUtil.isBlank(token)) {
			return null;
		}
		UserLogin userLogin = userLoginDao.getByToken(token);
		if (userLogin == null) {
			return null;
		}
		UserBase userBase = userBaseService.getById(userLogin.getId());
		if (userBase == null) {
			return null;
		}
		UserLoginVo userLoginVo = new UserLoginVo();
		if (userLogin.getHasIdentityAuth() != null
				&& userLogin.getHasIdentityAuth().intValue() == YesNoEnum.YES.getCode()) {
			userLoginVo.setHasIdentityAuth(YesNoEnum.YES.getCode());
		} else {
			userLoginVo.setHasIdentityAuth(YesNoEnum.NO.getCode());
		}
		if (userLogin.getHasCommunityAuth() != null
				&& userLogin.getHasCommunityAuth().intValue() == YesNoEnum.YES.getCode()) {
			userLoginVo.setHasCommunityAuth(YesNoEnum.YES.getCode());
		} else {
			userLoginVo.setHasCommunityAuth(YesNoEnum.NO.getCode());
		}
		userLoginVo.setId(userLogin.getId());
		userLoginVo.setToken(token);
		userLoginVo.setTokenExpireAt(userLogin.getTokenExpireAt());
		String nick = userSysParamCache.get(UserConst.PARAMKEY_USER_NICK_DEFAULT, "(未设昵称)");
		userLoginVo.setNick(userBase.getNick());
		if (StringUtil.isNotBlank(userBase.getNick())) {
			nick = userBase.getNick();
		}
		userLoginVo.setNick(nick);
		String logo = userSysParamCache.get(UserConst.PARAMKEY_USER_LOGO_DEFAULT, "source://image/user.jpg");
		if (StringUtil.isNotBlank(userBase.getLogo())) {
			logo = SettingCfgUtil.getConfigHelper("core.properties").getValue("core.file.domain",
					CoreConst.PARAMVALUE_CORE_FILE_DOMAIN) + "" + userBase.getLogo();
		}
		userLoginVo.setLogo(logo);
		UserIdentity userIdentity = new UserIdentity();
		userIdentity.setUserId(userLogin.getId());
		List<UserIdentity> listUserIdentity = userIdentityService.queryList(userIdentity);
		if (listUserIdentity == null || listUserIdentity.size() == 0) {
			return null;
		}
		for (UserIdentity userIdentity2 : listUserIdentity) {
			if (UserIdentityTypeDictEnum.PHONE.getCode() == userIdentity2.getType()) {
				userLoginVo.setPhone(userIdentity2.getIdentity());
			}
		}
		if (userBase.getHasIdentityAuth().intValue() == YesNoEnum.YES.getCode()) {// 已经实名
			UserAuth userAuth = userAuthService.getByUserId(userBase.getId());
			if (userAuth != null) {
				userLoginVo.setName(userAuth.getRealName());
			}
		}
		return userLoginVo;
	}

	@Override
	public Result doRegister(String identity, String verifycode, UserIdentityTypeDictEnum identityType,
			String deviceId) {
		Result result = new Result();
		if (identityType == null) {
			identityType = UserIdentityTypeDictEnum.PHONE;
		}
		if (StringUtil.isBlank(identity)) {
			if (UserIdentityTypeDictEnum.PHONE.equals(identityType)) {
				result.addErr("手机号码不能为空");
			} else {
				result.addErr("注册账号不能为空");
			}
		} else {
			if (UserIdentityTypeDictEnum.PHONE.equals(identityType)) {
				if (!StringUtil.isPhone(identity)) {
					result.addErr("手机号码不正确");
				}
			}
		}
		if (StringUtil.isBlank(verifycode)) {
			result.addErr("注册验证码不能为空");
		}
		if (!result.checkForm()) {
			return result;
		}
		// 判断账号重复
		if (userIdentityService.isDuplicate(identity, identityType)) {
			result.addErr("账号" + identity + "已被注册");
			return result;
		}
		// 判断验证码是否有效
		result = userVerifycodeService.checkValidCode(identity, verifycode, UserVerifycodeTypeDictEnum.REG_LOGIN);
		if (!result.checkForm()) {
			return result;
		}
		if (StringUtil.isNotBlank(deviceId)) {
			UserBase userBase = new UserBase();
			userBase.setDeviceId(deviceId);
			int i = userBaseService.queryCount(userBase);
			if (i > 0) {
				result.addErr("同一手机不能注册多个账号");
				return result;
			}
		}
		Integer verifycodeId = (Integer) result.get("verifycodeId");
		// 把验证码状态变更为已验证
		UserVerifycode userVerifycode = new UserVerifycode();
		userVerifycode.setId(verifycodeId);
		userVerifycode.setIsVerify(YesNoEnum.YES.getCode());
		userVerifycode.setUpdAt(TimeUtil.now());
		userVerifycodeService.updateById(userVerifycode);
		UserLoginVo userLoginVo = doAddNewUser(identity, identityType, deviceId);
		result.put("loginUser", userLoginVo);
		return result;
	}

	@Override
	public Result doLoginWithPhoneCode(String phone, String verifycode, String deviceId) {
		Result result = new Result();
		if (StringUtil.isBlank(phone)) {
			result.addErr("手机号码不能为空");
		} else {
			if (!StringUtil.isPhone(phone)) {
				result.addErr("手机号码不正确");
			}
		}
		if (StringUtil.isBlank(verifycode)) {
			result.addErr("验证码不能为空");
		}
		if (!result.checkForm()) {
			return result;
		}
		// 判断验证码是否有效
		result = userVerifycodeService.checkValidCode(phone, verifycode, UserVerifycodeTypeDictEnum.REG_LOGIN);
		if (!result.checkForm()) {
			return result;
		}
		boolean isDuplicate = true;
		// 判断该手机号是否已被注册
		if (!userIdentityService.isDuplicate(phone, UserIdentityTypeDictEnum.PHONE)) {
			isDuplicate = false;
			if (StringUtil.isNotBlank(deviceId)) {
				UserBase userBase = new UserBase();
				userBase.setDeviceId(deviceId);
				int i = userBaseService.queryCount(userBase);
				if (i > 0) {
					result.addErr("同一手机不能注册多个账号");
					return result;
				}
			}
		}
		Integer verifycodeId = (Integer) result.get("verifycodeId");
		// 把验证码状态变更为已验证
		UserVerifycode userVerifycode = new UserVerifycode();
		userVerifycode.setId(verifycodeId);
		userVerifycode.setIsVerify(YesNoEnum.YES.getCode());
		userVerifycode.setUpdAt(TimeUtil.now());
		userVerifycodeService.updateById(userVerifycode);
		UserLoginVo userLoginVo = new UserLoginVo();
		// 判断该手机号是否已被注册
		if (!isDuplicate) {
			userLoginVo = doAddNewUser(phone, UserIdentityTypeDictEnum.PHONE, deviceId);
			result.put("register", "1");
			result.put("strPwd", userLoginVo.getStrPwd());
			result.put("nick", userLoginVo.getNick());
		} else {
			UserIdentityVo userIdentityVo = userIdentityService.getIdentityByType(phone,
					UserIdentityTypeDictEnum.PHONE);
			updateLoginToken(userIdentityVo.getUserId());
			userLoginVo = getById(userIdentityVo.getUserId());
			result.put("register", "0");
			UserBase userBase = userBaseService.getById(userIdentityVo.getUserId());
			result.put("logo", userBase.getFileDomain() + userBase.getLogo());
			result.put("nick", userBase.getNick());
		}
		result.put("loginUser", userLoginVo);
		result.put("loginUserId", userLoginVo.getId());
		if (userLoginVo != null && userLoginVo.getHasIdentityAuth() != null
				&& userLoginVo.getHasIdentityAuth().intValue() == YesNoEnum.YES.getCode()) {
			result.put("hasIdentityAuth", 1);
		} else {
			result.put("hasIdentityAuth", 2);
		}
		if (userLoginVo != null && userLoginVo.getHasCommunityAuth() != null
				&& userLoginVo.getHasCommunityAuth().intValue() == YesNoEnum.YES.getCode()) {
			result.put("hasCommunityAuth", 1);
		} else {
			result.put("hasCommunityAuth", 2);
		}
		return result;
	}

	/**
	 * 变化用户的登录token
	 * 
	 * @param userId
	 * @return
	 */
	private int updateLoginToken(int userId) {
		UserLogin userLogin = new UserLogin();
		userLogin.setId(userId);
		UserLoginVo userLoginVo = userLoginService.getById(userId);
		if (null != userLoginVo && StringUtil.isNotBlank(userLoginVo.getToken())) {
			clear(userLoginVo.getToken());
		}
		userLogin.setToken(StringUtil.generateToken());
		int hours = userSysParamCache.getInt(UserConst.PARAMKEY_USER_LOGIN_TOKEN_EXPIRE, 30 * 24);
		userLogin.setTokenExpireAt(TimeUtil.addMins(TimeUtil.now(), hours * 60));
		return userLoginService.updateById(userLogin);
	}

	@Override
	public Result doLoginWithPhonePwd(String phone, String password) {
		Result result = new Result();
		if (StringUtil.isBlank(phone)) {
			result.addErr("手机号码不能为空");
		} else {
			if (!StringUtil.isPhone(phone)) {
				result.addErr("手机号码不正确");
			}
		}
		if (StringUtil.isBlank(password)) {
			result.addErr("密码不能为空");
		}
		if (!result.checkForm()) {
			return result;
		}
		UserIdentity userIdentity = new UserIdentity();
		userIdentity.setIdentity(phone);
		userIdentity.setType(UserIdentityTypeDictEnum.PHONE.getCode());
		userIdentity = userIdentityDao.getOne(userIdentity);
		if (userIdentity != null) {
			UserLogin userLogin = userLoginDao.getById(userIdentity.getUserId());
			if (userLogin != null) {
				if (StringUtil.shaEncode(password).equals(userLogin.getPasswod())) {
					updateLoginToken(userLogin.getId());
					result.put("loginUser", getById(userLogin.getId()));
					UserBase userBase = userBaseService.getById(userLogin.getId());
					result.put("logo", userBase.getFileDomain() + userBase.getLogo());
					result.put("nick", userBase.getNick());
					if (userLogin != null && userLogin.getHasIdentityAuth() != null
							&& userLogin.getHasIdentityAuth().intValue() == YesNoEnum.YES.getCode()) {
						result.put("hasIdentityAuth", 1);
					} else {
						result.put("hasIdentityAuth", 2);
					}
					if (userLogin != null && userLogin.getHasCommunityAuth() != null
							&& userLogin.getHasCommunityAuth().intValue() == YesNoEnum.YES.getCode()) {
						result.put("hasCommunityAuth", 1);
					} else {
						result.put("hasCommunityAuth", 2);
					}
					result.put("loginUserId", userLogin.getId());
					return result;
				}
			}
		}
		result.addErr("手机或密码不正确");
		return result;
	}

	/**
	 * 数据库新增用户
	 * 
	 * @param identity
	 * @param typeEnum
	 * @param deviceId
	 * @return
	 */
	private UserLoginVo doAddNewUser(String identity, UserIdentityTypeDictEnum typeEnum, String deviceId) {
		// 对用户的数据库操作
		UserBase userBase = new UserBase();
		userBase.setHasIdentityAuth(YesNoEnum.NO.getCode());
		String nick = identity;
		if (nick.length() > 6) {
			nick = "**" + nick.substring(nick.length() - 6, nick.length());
		}
		userBase.setNick(nick);
		userBase.setLogo("/user/userLogin.png");
		userBase.setChnSpell("");
		userBase.setIsOfficial(YesNoEnum.NO.getCode());
		userBase.setDeviceId(deviceId);
		userBase.setSex(SexEnum.FEMALE.getCode());
		// 默认加入桃源居
		//int communityId = 100004;
		//userBase.setCommunityId(communityId);
		int userId = userBaseService.insert(userBase);

		UserIdentity userIdentity = new UserIdentity();
		userIdentity.setUserId(userId);
		userIdentity.setIdentity(identity);
		userIdentity.setType(typeEnum.getCode());
		userIdentityService.insert(userIdentity);
		UserLogin userLogin = new UserLogin();
		String password = StringUtil.getRandomNum(6);
		userLogin.setId(userId);
		userLogin.setPasswod(StringUtil.shaEncode(password));
		userLogin.setToken(StringUtil.generateToken());
		int hours = userSysParamCache.getInt(UserConst.PARAMKEY_USER_LOGIN_TOKEN_EXPIRE, 30 * 24);
		userLogin.setTokenExpireAt(TimeUtil.addMins(TimeUtil.now(), hours * 60));
		userLogin.setHasCommunityAuth(YesNoEnum.NO.getCode());
		userLogin.setHasIdentityAuth(YesNoEnum.NO.getCode());
		userLoginService.insert(userLogin);

		UserValue userValue = new UserValue();
		userValue.setId(userId);
		userValue.setMoney(0);
		userValue.setQuanValue(0);
		userValue.setIsBackground(YesNoEnum.NO.getCode());
		userValue.setIsShowLocation(YesNoEnum.NO.getCode());
		userValue.setOsType(UserValueOsTypeDictEnum.ANDROID.getCode());
		userValue.setDrawCount(0);
		userValue.setHonorValue(0);
		userValue.setHonorLevelName("v0");
		userValue.setHonorLevel(0);
		userValueService.insert(userValue);

		imUserService.addImUser(userId, userBase.getNick());// IM添加用户
		UserLoginVo userLoginVo = this.getByToken(userLogin.getToken());
		userLoginVo.setStrPwd(password);
		userLoginVo.setNick(nick);
		// 新用户奖励周边商家满20减5元的优惠卷
		String userRegisterAwardStartTime = userSysParamCache.get(UserConst.PARAMKEY_USER_REGISTER_AWARD_START_TIME);
		String userRegisterAwardEndTime = userSysParamCache.get(UserConst.PARAMKEY_USER_REGISTER_AWARD_END_TIME);
		if (StringUtil.isNotBlank(userRegisterAwardStartTime) && StringUtil.isNotBlank(userRegisterAwardEndTime)) {
			if (TimeUtil.now().before(TimeUtil.getTimeByFormat(userRegisterAwardEndTime, TimeUtil.DATE_TIME_FORMAT))
					&& TimeUtil.now()
							.after(TimeUtil.getTimeByFormat(userRegisterAwardStartTime, TimeUtil.DATE_TIME_FORMAT))) {
				CouponBaseQuery query = new CouponBaseQuery();
				query.setName("新用户注册");//like查询
				query.setStatus(1);
				//query.setBizzType(CouponBaseBizzTypeDictEnum.NEARBY_MALL.getCode());
				Pageable pageKit = new PageKit(1, 1, new PageOrder(Direction.DESC, "id"));
				List<CouponBaseVo> list = couponBaseService.queryList(query, pageKit);
				if (null != list && list.size() > 0) {
					couponUserService.addCouponUser(userId, list.get(0).getId(), CouponUserObtainWayDictEnum.AWARD,
							null);
				}

			}
		}
		// 初始化新手任务
		hiUserTaskService.initTask4User(userId, HiRuleTaskTypeDictEnum.NOVICE);
		// 注册得荣誉值
		hiUserService.register(userId);
		// 默认加入社区得荣誉系统奖励
		//hiCommunityService.join(userId, communityId);
		return userLoginVo;
	}

	@Override
	public void doChangePwd(Integer userId, String password) throws BizzException {
		if (userId == null || userId.intValue() == 0 || StringUtil.isBlank(password)) {
			throw new BizzException("用户数据发生异常");
		}
		UserLogin userLogin = userLoginDao.getById(userId);
		if (userLogin == null) {
			throw new BizzException("用户数据不存在，请联系管理员");
		}
		userLogin = new UserLogin();
		userLogin.setId(userId);
		userLogin.setPasswod(StringUtil.shaEncode(password));
		userLoginDao.updateById(userLogin);
	}

	@Override
	public Result initUser(Integer userId, String password, String nick) throws BizzException {
		if (userId == null || userId.intValue() == 0) {
			throw new BizzException("用户数据发生异常");
		}
		Result result = new Result();
		boolean isUpdate = false;
		if (StringUtil.isNotBlank(password)) {
			UserLogin userLogin = new UserLogin();
			userLogin.setId(userId);
			userLogin.setPasswod(StringUtil.shaEncode(password));
			userLoginDao.updateById(userLogin);
			isUpdate = true;
		}
		if (StringUtil.isNotBlank(nick)) {
			UserBase userBase = new UserBase();
			userBase.setId(userId);
			userBase.setNick(nick);
			String pinYin4Nick = PinyingUtil.hanziToPinyinNoSpace(userBase.getNick()).toUpperCase();
			if (StringUtil.isNotBlank(pinYin4Nick)) {
				userBase.setChnSpell(pinYin4Nick);// 全拼大写
			}
			userBaseService.updateById(userBase);
			hiUserService.editNick(userBase.getId());// 荣誉系统-修改呢称
			result.put("nick", nick);
			isUpdate = true;
		}
		if (isUpdate == true) {
			UserLogin userLogin = userLoginDao.getById(userId);
			if (userLogin != null && StringUtil.isNotBlank(userLogin.getToken())) {
				this.clear(userLogin.getToken());
			}
		}
		return result;
	}

	@Override
	public Result doChangePwdWithVerifycode(Integer userId, String password, String verifycode) {
		Result result = new Result();
		if (StringUtil.isBlank(verifycode)) {
			result.addErr("验证码不能为空");
		}
		if (StringUtil.isBlank(password)) {
			result.addErr("修改密码不能为空");
		}
		UserLogin userLogin = userLoginDao.getById(userId);
		if (userLogin == null) {
			result.addErr("用户数据不存在，请联系管理员");
		}
		UserIdentityQuery userIdentityQuery = new UserIdentityQuery();
		userIdentityQuery.setUserId(userId);
		userIdentityQuery.setType(UserIdentityTypeDictEnum.PHONE.getCode());
		UserIdentityVo userIdentityVo = userIdentityService.getOne(userIdentityQuery, new PageOrder());
		// 判断验证码是否有效
		result = userVerifycodeService.checkValidCode(userIdentityVo.getIdentity(), verifycode,
				UserVerifycodeTypeDictEnum.CHANGEPASSWORD);
		if (!result.checkForm()) {
			return result;
		}
		Integer verifycodeId = (Integer) result.get("verifycodeId");
		// 把验证码状态变更为已验证
		UserVerifycode userVerifycode = new UserVerifycode();
		userVerifycode.setId(verifycodeId);
		userVerifycode.setIsVerify(YesNoEnum.YES.getCode());
		userVerifycode.setUpdAt(TimeUtil.now());
		userVerifycodeService.updateById(userVerifycode);

		userLogin = new UserLogin();
		userLogin.setId(userId);
		userLogin.setPasswod(StringUtil.shaEncode(password));
		userLoginDao.updateById(userLogin);
		return result;
	}

	@Override
	public boolean isCommunityAuth(Integer userId) {
		UserLoginVo userLoginVo = userLoginDao.getById(userId);
		if (YesNoEnum.YES.getCode() == userLoginVo.getHasCommunityAuth()) {
			return true;
		}
		return false;
	}
}